package main

import "fmt"

func main() {

	/**
	五. 闭包。闭包指的是一个函数和与其相关的引用环境组合而成的实体。简单来说，闭包=函数+引用环境

	*/

	// intSeq()函数返回一个在其函数体内定义的匿名函数。返回的函数使用闭包的方式隐藏变量i
	seq := intSeq()
	fmt.Println("闭包1", seq(1)) // 1
	fmt.Println("闭包1", seq(2)) // 3
	fmt.Println("闭包1", seq(3)) // 6
	fmt.Println("闭包1", seq(4)) // 10

	f := intSeq()
	fmt.Println("闭包2", f(20)) // 20
	fmt.Println("闭包2", f(20)) // 40
	fmt.Println("闭包2", f(10)) // 50

	// 斐波那契数列：公式f[n]=f[n-1]+f[n-2]
	// 1 1 2 3 5 8 13 21 34 ........
	// a b
	//   a b
	// 	   a b
	// 		....
	fibonacci := fibonacci()
	for i := 0; i < 20; i++ {
		fmt.Println("fibonacci: ", fibonacci())
	}
}

func fibonacci() func() int {

	// f(0) = 1, f(1) = 1
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return a
	}
}

/*
返回值为一个函数变量
*/
func intSeq() func(val int) int {

	i := 0
	// 使用了匿名函数。因为函数内部没办法声明带名字的函数，所以匿名函数经常被用于实现回调函数、闭包等
	// 匿名函数是指在代码中没有明确命名的函数，闭包是一个函数值，它可以访问其词法环境中捕获的变量。匿名函数可以是闭包，也可以不是闭包。匿名函数引用了外部作用域中的变量，它就成为闭包
	// 更多可见：https://juejin.cn/post/7299859799780786227
	return func(val int) int {
		i += val
		return i
	}
}
